package com.appistry.management.domain.impl;

import java.io.InputStream;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.appistry.api.rest.domain.RestResponse;
import com.appistry.management.Application;
import com.appistry.management.ConsoleExtension;
import com.appistry.management.Fabric;
import com.appistry.management.FabricArchive;
import com.appistry.management.FabricFile;
import com.appistry.management.FabricInfo;
import com.appistry.management.FabricOverview;
import com.appistry.management.Manifest;
import com.appistry.management.ManifestEntry;
import com.appistry.management.Service;
import com.appistry.management.ShutdownList;
import com.appistry.management.State;
import com.appistry.management.Worker;
import com.appistry.management.WorkerPerformanceInfo;
import com.appistry.management.domain.AbstractRestDomainObject;
import com.appistry.management.domain.ControllerAction;
import com.appistry.management.exception.FabricManagerException;
import com.appistry.management.rest.RestFabricManager;
import com.appistry.management.util.JsonTransformUtil;

public class FabricImpl extends AbstractRestDomainObject implements Fabric {
	RestFabricManager restFabricManager;

	public FabricImpl(RestFabricManager restFabricManager) {
		this.restFabricManager = restFabricManager;
	}

	public void deleteShutdownList() throws FabricManagerException {
		try {
			RestResponse restResponse = restFabricManager.deleteShutdownList();
			checkForErrors(restResponse);
		} catch (Exception e) {
			throw new FabricManagerException(e);
		}
	}

	public List<Application> getApplications(boolean showDeleted) throws FabricManagerException {
		try {
			RestResponse restResponse = restFabricManager.getApplicationList(showDeleted);
			checkForErrors(restResponse);

			List<Application> apps = JsonTransformUtil.toApplicationList(restFabricManager, restResponse.getBodyAsString());

			return apps;
		} catch (JSONException e) {
			throw new FabricManagerException(PARSE_JSON_ERR, e);
		} catch (Exception e) {
			throw new FabricManagerException(e);
		}
	}

	public List<ConsoleExtension> getConsoleExtensions() throws FabricManagerException {
		try {
			RestResponse restResponse = restFabricManager.getConsoleExtensions();
			checkForErrors(restResponse);

			List<ConsoleExtension> consoleExtensions = JsonTransformUtil.toConsoleExtensionList(restResponse.getBodyAsString());

			return consoleExtensions;
		} catch (JSONException e) {
			throw new FabricManagerException(PARSE_JSON_ERR, e);
		} catch (Exception e) {
			throw new FabricManagerException(e);
		}
	}

	public List<FabricArchive> getFabricArchives(boolean showDeleted) throws FabricManagerException {
		try {
			RestResponse restResponse = restFabricManager.getFabricArchiveList(showDeleted);
			checkForErrors(restResponse);

			List<FabricArchive> fars = JsonTransformUtil.toFabricArchiveList(restFabricManager, restResponse.getBodyAsString());

			return fars;
		} catch (JSONException e) {
			throw new FabricManagerException(PARSE_JSON_ERR, e);
		} catch (Exception e) {
			throw new FabricManagerException(e);
		}
	}

	public FabricInfo getFabricInfo() throws FabricManagerException {
		try {
			RestResponse restResponse = restFabricManager.getFabricInfo();
			checkForErrors(restResponse);

			FabricInfo fabricInfo = JsonTransformUtil.toFabricInfo(restResponse.getBodyAsString());

			return fabricInfo;
		} catch (JSONException e) {
			throw new FabricManagerException(PARSE_JSON_ERR, e);
		} catch (Exception e) {
			throw new FabricManagerException(e);
		}
	}

	public FabricOverview getFabricOverview() throws FabricManagerException {
		try {
			RestResponse restResponse = restFabricManager.getFabricOverview();
			checkForErrors(restResponse);

			FabricOverview fabricOverview = JsonTransformUtil.toFabricOverview(restResponse.getBodyAsString());

			return fabricOverview;
		} catch (JSONException e) {
			throw new FabricManagerException(PARSE_JSON_ERR, e);
		} catch (Exception e) {
			throw new FabricManagerException(e);
		}
	}

	public Map<InetAddress, WorkerPerformanceInfo> getFabricPerformanceInfo() throws FabricManagerException {
		try {
			RestResponse restResponse = restFabricManager.getFabricPerformanceInfo();
			checkForErrors(restResponse);

			Map<InetAddress, WorkerPerformanceInfo> map = JsonTransformUtil.toFabricPerformanceInfo(restResponse.getBodyAsString());

			return map;
		} catch (JSONException e) {
			throw new FabricManagerException(PARSE_JSON_ERR, e);
		} catch (Exception e) {
			throw new FabricManagerException(e);
		}
	}

	public InputStream getFile(String fileName) throws FabricManagerException {
		try {
			RestResponse restResponse = restFabricManager.getFileManagement(fileName);
			checkForErrors(restResponse);

			return restResponse.getBodyAsStream();
		} catch (Exception e) {
			throw new FabricManagerException(e);
		}
	}

	public boolean deleteFile(String fileName) throws FabricManagerException {
		try {
			RestResponse restResponse = restFabricManager.deleteFileManagement(fileName);
			checkForErrors(restResponse);

			return true;
		} catch (Exception e) {
			throw new FabricManagerException(e);
		}
	}

	public List<FabricFile> getFileList() throws FabricManagerException {
		try {
			RestResponse restResponse = restFabricManager.getFileList();
			checkForErrors(restResponse);

			List<FabricFile> files = JsonTransformUtil.toFabricFilesList(restFabricManager, restResponse.getBodyAsString());

			return files;
		} catch (JSONException e) {
			throw new FabricManagerException(PARSE_JSON_ERR, e);
		} catch (Exception e) {
			throw new FabricManagerException(e);
		}
	}

	public Manifest getManifest() throws FabricManagerException {
		try {
			RestResponse restResponse = restFabricManager.getManifest();
			checkForErrors(restResponse);

			Manifest manifest = JsonTransformUtil.toManifest(restResponse.getBodyAsString());

			return manifest;
		} catch (JSONException e) {
			throw new FabricManagerException(PARSE_JSON_ERR, e);
		} catch (Exception e) {
			throw new FabricManagerException(e);
		}
	}

	public ManifestEntry getManifestEntry(String entry) throws FabricManagerException {
		try {
			RestResponse restResponse = restFabricManager.getManifestEntry(entry);
			checkForErrors(restResponse);

			ManifestEntry manifestEntry = JsonTransformUtil.toManifestEntry(restResponse.getBodyAsString());

			return manifestEntry;
		} catch (JSONException e) {
			throw new FabricManagerException(PARSE_JSON_ERR, e);
		} catch (Exception e) {
			throw new FabricManagerException(e);
		}
	}

	public List<ManifestEntry> getManifestEntryList() throws FabricManagerException {
		// TODO change to not get the whole thing at once.. make it smarter
		try {
			RestResponse restResponse = restFabricManager.getManifestEntryList();
			checkForErrors(restResponse);

			ArrayList<ManifestEntry> entries = new ArrayList<ManifestEntry>();
			JSONArray jsonArray = new JSONArray(restResponse.getBodyAsString());
			for (int i = 0; i < jsonArray.length(); i++) {
				JSONObject jsonObj = jsonArray.getJSONObject(i);
				String entry = jsonObj.getString("entry");
				entries.add(getManifestEntry(entry));
			}

			return entries;
		} catch (JSONException e) {
			throw new FabricManagerException(PARSE_JSON_ERR, e);
		} catch (Exception e) {
			throw new FabricManagerException(e);
		}
	}

	public List<Service> getServices() throws FabricManagerException {
		try {
			RestResponse restResponse = restFabricManager.getServicesList();
			checkForErrors(restResponse);

			List<Service> apps = JsonTransformUtil.toServiceList(restFabricManager, restResponse.getBodyAsString());

			return apps;
		} catch (JSONException e) {
			throw new FabricManagerException(PARSE_JSON_ERR, e);
		} catch (Exception e) {
			throw new FabricManagerException(e);
		}
	}

	public ShutdownList getShutdownList() throws FabricManagerException {
		try {
			RestResponse restResponse = restFabricManager.getShutdownList();
			checkForErrors(restResponse);

			ShutdownList shutdownList = JsonTransformUtil.toShutdownList(restResponse.getBodyAsString());

			return shutdownList;
		} catch (JSONException e) {
			throw new FabricManagerException(PARSE_JSON_ERR, e);
		} catch (Exception e) {
			throw new FabricManagerException(e);
		}
	}

	public List<Worker> getWorkers() throws FabricManagerException {
		try {
			RestResponse restResponse = restFabricManager.getWorkerList();
			checkForErrors(restResponse);

			List<Worker> workers = JsonTransformUtil.toWorkerList(restFabricManager, restResponse.getBodyAsString());

			return workers;
		} catch (JSONException e) {
			throw new FabricManagerException(PARSE_JSON_ERR, e);
		} catch (Exception e) {
			throw new FabricManagerException(e);
		}
	}

	public void putFabricInfo(FabricInfo fabricInformation) throws FabricManagerException {
		try {
			JSONObject jsonObject = new JSONObject();
			jsonObject.put("name", fabricInformation.getName());
			jsonObject.put("description", fabricInformation.getName());

			RestResponse restResponse = restFabricManager.putFabricInfo(jsonObject.toString());
			checkForErrors(restResponse);
		} catch (JSONException e) {
			throw new FabricManagerException(PARSE_JSON_ERR, e);
		} catch (Exception e) {
			throw new FabricManagerException(e);
		}
	}

	public void putFile(String fileName, InputStream content) throws FabricManagerException {
		try {
			RestResponse restResponse = restFabricManager.putFileManagement(fileName, content);
			checkForErrors(restResponse);

		} catch (Exception e) {
			throw new FabricManagerException(e);
		}
	}

	public void reboot() throws FabricManagerException {
		fabricController(ControllerAction.REBOOT);
	}

	public void start() throws FabricManagerException {
		fabricController(ControllerAction.START);
	}

	public void stop() throws FabricManagerException {
		fabricController(ControllerAction.STOP);
	}

	public void kill() throws FabricManagerException {
		fabricController(ControllerAction.KILL);
	}

	private boolean fabricController(ControllerAction action) throws FabricManagerException {
		try {
			RestResponse restResponse = restFabricManager.fabricController(action);
			checkForErrors(restResponse);

			return true;
		} catch (Exception e) {
			throw new FabricManagerException(e);
		}
	}

	public Map<InetAddress, State> getState() throws FabricManagerException {
		try {
			RestResponse restResponse = restFabricManager.getFabricState();
			checkForErrors(restResponse);

			Map<InetAddress, State> workerStateMap = JsonTransformUtil.toWorkerStateMap(restResponse.getBodyAsString());

			return workerStateMap;
		} catch (JSONException e) {
			throw new FabricManagerException(PARSE_JSON_ERR, e);
		} catch (Exception e) {
			throw new FabricManagerException(e);
		}
	}

}
